/**
 * \file
 */
#ifndef kfs_hpp_included
#define kfs_hpp_included

#include <boost/scoped_ptr.hpp>
#include <string>
#include <vector>

typedef uint64_t file_size_t;
typedef uint32_t block_index_t;
typedef uint32_t block_off_t;

class FileDescriptor;
class Inode;
class InodeRef;

/**
 * Mount a file system and service file I/O operations.
 *
 * Operate on a block device.
 */
class kfs
{
public:

    /**
     * Mount a filesystem.  TODO: Accept an object with block device operations.
     */
    kfs(std::string const& deviceName);

    ~kfs();

    /**
     * Open the node specified by an absolute path.
     *
     * @return A file descriptor.  The caller is responsible to destroy it.
     */
    FileDescriptor*
    file_create(std::string const& path, int flags, mode_t mode, uid_t uid,
        gid_t gid);

    /**
     * Open the node specified by an absolute path.  This function operates on
     * directories.
     *
     * Access modes: O_RDONLY or O_WRONLY or O_RDWR
     *
     * Others: O_CREAT, O_TRUNC
     *
     * @param flags A bitmask consisting of one access mode and optionally,
     * other symbols.
     *
     * @return A file descriptor.  The caller is responsible to destroy it.
     */
    FileDescriptor*
    file_open(std::string const& path, int flags);

    FileDescriptor*
    file_open(block_index_t const& inodeBlockNum, std::string const& path,
        int flags);

    void
    file_close(FileDescriptor* file);

    void unlink(std::string const& path);

    void test_getBlockNumber(Inode const* inode);

    void test_resolveDiskBlock();

//private:

    class Impl;
    boost::scoped_ptr<Impl> impl;
};

class InitParams
{
public:

    InitParams();
    uint16_t blockNumBytes;
    std::string deviceName;
};

/**
 * Serialized size: 1*8 + 3*2 + 3*8 + 1*4 + 15*4 = 102 bytes
 */
class Inode
{
public:

    //Inode();

    static uint32_t Magic;

    file_size_t sizeNumBytes;      ///< Size of the file, in bytes.
    uint16_t userID;               ///< Ownership user ID
    uint16_t groupID;              ///< Ownership group ID
    uint32_t mode;                 ///< Bit vector: permissions, types, etc.
    uint64_t ctime;                ///< Inode change time
    uint64_t mtime;                ///< File content last-modified time
    uint64_t atime;                ///< File last accessed time
    uint32_t linkCount;            ///< Link count: how many hard links point to the inode.
    /** Pointers to the disk blocks that store the file's contents, as follows.
     * Twelve pointers that directly point to blocks of the file's data (direct
     * pointers).
     * One singly indirect pointer (a pointer that points to a block of
     * pointers that then point to blocks of the file's data).
     * One doubly indirect pointer (a pointer that points to a block of
     * pointers that point to other blocks of pointers that then point to
     * blocks of the file's data).
     * One triply indirect pointer (a pointer that points to a block of
     * pointers that point to other blocks of pointers that point to other
     * blocks of pointers that then point to blocks of the file's data).
     */
    std::vector<uint32_t> dataBlockAddresses;
    //uint32_t dataBlockAddresses[15];
};

class InodeRef
{
public:

    block_index_t diskBlockNum;
    Inode inode;
};

/*
The following flags are defined for the st_mode field:

    S_IFMT     0170000   bit mask for the file type bit fields
    S_IFSOCK   0140000   socket
    S_IFLNK    0120000   symbolic link
    S_IFREG    0100000   regular file
    S_IFBLK    0060000   block device
    S_IFDIR    0040000   directory
    S_IFCHR    0020000   character device
    S_IFIFO    0010000   FIFO
    S_ISUID    0004000   set UID bit
    S_ISGID    0002000   set-group-ID bit (see below)
    S_ISVTX    0001000   sticky bit (see below)
    S_IRWXU    00700     mask for file owner permissions
    S_IRUSR    00400     owner has read permission
    S_IWUSR    00200     owner has write permission
    S_IXUSR    00100     owner has execute permission
    S_IRWXG    00070     mask for group permissions
    S_IRGRP    00040     group has read permission
    S_IWGRP    00020     group has write permission
    S_IXGRP    00010     group has execute permission
    S_IRWXO    00007     mask for permissions for others (not in group)
    S_IROTH    00004     others have read permission
    S_IWOTH    00002     others have write permission
    S_IXOTH    00001     others have execute permission

*/

#endif // kfs_hpp_included
